<?php
/**
* File, which contains <Auth> class
*
* @package Temply-Account\Services
* @author Sergey Dilong
* @license GPL-2.0
*/
/**
* Authorization and current account control
*
* Used to all auth purposes and getting current user info
*
* @package Temply-Account\Services
* @author Sergey Dilong
* @license GPL-2.0
*/
class Auth
{
/** @var string 64 symbols unique access key
* @see Auth::getTokenData() Get token outside the class
*/
private $token = false;
/** @var mixed[] Current user info
* @see Auth::User() Get current User
*/
private static $data = [];
/** @var bool Checks if Auth() was already inited
* @see Auth::Init() Look up where it is used
*/
private static $init = false;
/**
* Launch Auth system
*
* @param string $act Navigator string
* * *auth* - New login. Uses user-passed credentials (`login` and `password` fields)
* * *checkToken* - Just check token without other instances
* * *<empty\>* - Requires login
* @example "methods/Test/Server.php" 99 7 Auth could be called by statements
* @throws apiException
* * [300] DB Error
* * [301] Invalid credentials for login
* * [302] There's no such token in DB
*
* @see Auth::newToken() Login function
* @see Auth::check() Login check function
* @see Auth::getTokenData() Get token outside the class
* @see Auth::User() Get current User
*/
public function __construct($act = '')
{
// TODO: Custom fields to auth
global $secure;
if ($act === 'auth') {
// login
$this->newToken($secure['login'], $secure['password']);
} else {
// If not needed - simplified check
if ($act != 'checkToken') {
api::required("token");
}
// Check the token
$this->check($secure['token']);
}
}
/**
* New token
*
* Auth with login and password
*
* @param string $l Login
* @param string $p Password
*
* @throws apiException
* * [300] DB Error
* * [301] Invalid credentials for login
* @return bool If `true` - login successful
* @see Auth::__construct() Use this method outside the class
* @api
*/
private function newToken($l, $p)
{
// Get DB
// TODO: Remove $pdo shil
/** @deprecated */
global $pdo;
// Get User
$u = new User($l, ['GET_MODE' => "login", 'GET_UNSECURE_DATA' => true]);
$ud = $u->get();
// If incorrect password - throw an exception
if (!password_verify($p, $ud['__protect']['password'])) {
throw new apiException(301);
}
// Trigger for an unique token
$unique_token = false;
while (!$unique_token) {
// Get new string for token
$selected_token = security::token_str();
// Check is it already exists
$utc = $pdo->prepare("SELECT COUNT(*) from `tokens` WHERE `token` = ?");
$utc->execute([$selected_token]);
// If not - exit the cycle
if ($utc->fetchColumn() == 0) {
$unique_token = true;
}
}
// Token data template
$ins = [
"token" => $selected_token,
"user_id" => $ud["id"],
"ip" => $_SERVER["REMOTE_ADDR"],
"ua" => $_SERVER["HTTP_USER_AGENT"],
];
// Write it to DB
$insq = db::values($ins);
$rc = $pdo->prepare("INSERT into `tokens` SET $insq");
$rc->execute($ins);
// If insertion failed - throw DB error
if (!intval($pdo->lastInsertId()) > 0) {
throw new apiException(300);
}
// Save new token in the class
$this->token = $ins['token'];
$this->check($this->token);
return true;
}
/**
* Check token
*
* Checks if given token is correct
*
* @param string $t 64-symbols long token
*
* @throws apiException
* * [302] Incorrect token
*
* @return bool If `true` - token is correct
* @see Auth::__construct() Call this method outside the class
* @api
*/
private function check($t)
{
// TODO: Token check for any string
global $pdo;
// If there's already verified data - return
if (self::getTokenData()["verify"]) {
return true;
}
// Get from DB
$q = $pdo->prepare("SELECT * from `tokens` WHERE `token` = :token");
$q->execute(["token" => $t]);
$l = $q->fetch();
// If there's no such token - throw an exception
if (!$l['id'] > 0) {
throw new apiException(302);
return false;
}
// Write data
$this->token = $l['token'];
$r = [];
$r["verify"] = 1;
$r['token'] = $l['token'];
// Save current user
$r['user'] = new User($l['user_id']);
$r['user_return'] = $r['user'];
$r['user_return']->ReInitUser(["U_GET" => true]);
// Record token data
self::record($r);
return true;
}
/**
* Prepare Auth system
*
* Generates template for login system (Later used for current token data).
*/
public static function Init()
{
if (self::$init) {
return;
}
self::$data = [
'user' => false,
'user_return' => false,
'token' => false,
'verify' => 0,
];
self::$init = true;
}
/**
* Write current user data
*
* Saves current user to class field
*
* @param array $data User's data
* @return void
* @uses Auth::$data to store data
* @see self::check() Where this function used
*
*/
private static function record($data)
{
self::$data = $data;
}
/**
* Get token, etc.
*
* Get such data as token and verify status
*
* @return array Token data
* * *token* - [string] 64-symbols length
* * *verify* - [boolean] if `true` - token is checked
*
* @uses self::$data as data source
* @api
*/
public static function getTokenData()
{
return ['token' => self::$data['token'], 'verify' => self::$data['verify']];
}
/**
* Current user
*
* Recieve current User object
*
* If $r === `true`: {@see User::get() User->get()} will be returned, else - class {@see \User User}
*
* @param bool $r Return switcher
*
* @return User|array
*
* @see User
*/
public static function User($r = false)
{
return (self::getTokenData()["verify"] ? ($r ? self::$data['user_return'] : self::$data['user']) : false);
}
}